package breadbox.client.files;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.zip.Inflater;
import java.util.zip.InflaterOutputStream;

import breadbox.client.logging.Log;
import breadbox.client.logging.Logger;

/**
 * Write a series of chunks to a file
 * @author Forrest
 *
 */
public class Unchunker {
	private List<Chunk> chunks;			// List of Chunks to write to unchunk
	private String filename;			// Filename to write Chunks to
	private boolean compression;		// Flag to indicate if a decompressor should be used
	
	/**
	 * Create a new Unchunker
	 * @param chunks List<Chunk> of input chunks
	 * @param filename String filename for output
	 */
	public Unchunker(List<Chunk> chunks, boolean modify_filename) {
		this.chunks = chunks;
		String f_name = chunks.get(0).filename;
		this.filename = f_name;
		if (modify_filename) {
			String f = chunks.get(0).filename;
			String[] file_parts = f.split("\\.");
			if (file_parts.length == 2) {
				this.filename = file_parts[0] + "_new." + file_parts[1];
			}
		}

		Log l = new Logger();
		try {
			this.compression = l.getCompression(f_name);
		} catch (FileNotFoundException e) {
			System.err.println("File not found: " + f_name);
		}
	}
	
	/**
	 * Set the filename for the Unchunker
	 * @param filename String filename for current Unchunker
	 */
	public void setFile(String filename) {
		this.filename = filename;
	}
	
	/**
	 * Set the list of Chunks for the Unchunker
	 * @param chunks List<Chunk> chunks for current Unchunker
	 */
	public void setChunks(List<Chunk> chunks) {
		this.chunks = chunks;
	}
	
	/**
	 * Take the current list of chunks and write out to a file
	 */
	public int unchunk() throws NullPointerException {
		// don't allow null chunks
		if (chunks == null) {
			System.err.println("Get error: Empty output data");
			return 1;
		}
		
		// set up file streams
		FileOutputStream file_out = null;
		InflaterOutputStream inflate_out = null;
		try {
			file_out = new FileOutputStream(filename);
			Inflater inf = new Inflater();
			inflate_out = new InflaterOutputStream(file_out, inf);
		} catch (FileNotFoundException e1) {
			System.err.println("File not found: " + filename);
			return 1;
		}
		
		// write out the chunks
		// use the synchronized block because of the synchronizedList
		synchronized(chunks) {
		    Iterator<Chunk> i = chunks.iterator(); // Must be in synchronized block
		    Chunk c;
			while (i.hasNext()) {
				c = i.next();
				try {
					if (compression) {
						inflate_out.write(c.getData());
					} else {
						file_out.write(c.getData());
					}
				} catch (IOException e) {
					System.err.println("Get error: Cannot write to file output buffer");
					return 1;
				}
			}
		}
		
		// close the streams
		try {
			if (compression) {
				inflate_out.close();
			}
			file_out.close();
		} catch (IOException e) {
			System.err.println("Compression error: Cannot close stream");
			return 1;
		}
		return 0;
	}
}
